from events import *
from utils import *

import socket
import threading


# Este arquivo contem as classes relacionadas com comunicacao
# com o servidor.

#------------------------------------------------------------------------------
# Some constants

HOST='localhost'
PORT=1939

class ClientCommunicationController(EventManager):
	def __init__(self, evManager, game):
		EventManager.__init__(self)

		self.evManager = evManager
		self.evManager.RegisterListener( self )
		
		self.game = game

		self.thread = None
		self.soc = None

		self.soc_lock = threading.RLock()

	def __enter__(self):
		pass

	def disconnectFromServer(self):
		if self.thread:
			self.thread.stop_running.set() 
		if self.soc:
			#poderiamos enviar uma mensagem de despedida talvez?
			self.soc.close()
			self.soc = None

	def connectToServer(self):
		# Just being sure that nothing will break
		self.disconnectFromServer()

		if self.thread:
			self.thread.stop_running.set() 
		if self.soc:
			self.soc.close()
			self.soc = None
		print "Openning new socket"
		self.soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		try:
			self.soc.connect((HOST, PORT))
			self.thread = ClientCommunicationThread(self)
			self.thread.start()
		except socket.error, msg:
			print str(msg)
			self.soc.close()
			self.thread = None
			self.soc = None
			return

	def __exit__(self, type, value, traceback):
		if self.soc:
			self.soc.close()
		if self.thread:
			self.thread.stop_running.set()

	def unpack_server_message(self, message):
		messplit = message.split(None, 1)
		if len(messplit) > 0:
			head = messplit[0]
		else:
			head = ''
		if len(messplit) > 1:
			tail = messplit[1]
		else:
			tail = ''
		if head == "falhaCadastro":
			ev = GUIDialogAddRequest('msgDialog', tail)
			self.evManager.Post( ev )
		if head == "cadastroOk":
                        ev = GUIWaitingDialogAddRequest('waitingDialog')
			self.evManager.Post( ev )
		if head == "serverReady":
			num, tail = tail.split(None, 1)
			player_territory = {}
			for i in range(int(num)):
				pname, numterritories, tail = tail.split(None, 2)
				numterritories = int(numterritories)
				territories = tail.split(None, numterritories)
				if len(territories) > numterritories:
					tail = territories[numterritories]
					territories = territories[0:numterritories]
				else:
					tail = ''
				player_territory[pname] = territories
			ev = GUIDialogRemoveRequest( 'waitingDialog' )
			self.evManager.Post( ev )
			ev2 = GameSetupRequest(player_territory)
			self.evManager.Post( ev2 )
			self.evManager.Flush()

	def register_to_the_server(self):
		self.connectToServer()
		mes = "cadastro "
		mes += self.game.current_player
		mes += " "
		mes += self.game.current_player_color
		mes += "\n"
		with self.soc_lock:
			self.soc.sendall(mes)

	def say_i_am_ready(self):
		with self.soc_lock:
			self.soc.sendall("ready\n")

	def Notify(self, event):
		if isinstance( event, GotMessageFromServerEvent ):
			print "Message from server:" + event.message
			self.unpack_server_message(event.message)
		elif isinstance( event, SendMessageToServerEvent ):
			#self.soc.sendall(event.message)
			pass
		elif isinstance( event, ConnectToServerEvent ):
			#self.connectToServer()
			#self.evManager.Post( SendMessageToServerEvent("hi\n") )
			pass
		elif isinstance( event, GameEndedEvent ):
			self.disconnectFromServer()
			print "Fim de jogo"
		elif isinstance( event, RegisterToTheServerEvent ):
			self.register_to_the_server()
		elif isinstance( event, ServerIAmReadyEvent ):
			self.say_i_am_ready()


class ClientCommunicationThread(threading.Thread):
	def __init__(self, ccController):
		threading.Thread.__init__(self)
		self.ccController = ccController
		self.stop_running = threading.Event()

	def getline(self):
		line = ''
		while not self.stop_running.isSet():
			try:
				with self.ccController.soc_lock:
					c = self.ccController.soc.recv(1, socket.MSG_DONTWAIT)
			except:
				break
			if len(c) < 1:
				break
			if c == '\n':
				line += '\n'
				break
			else:
				line += c
		return line

	def run(self):
		l = ''
		while not self.stop_running.isSet():
			try:
				l += self.getline()
				if len(l) > 0 and l[-1] == '\n':
					print "Got message %s. Trying to send." % l
					self.ccController.evManager.Post(GotMessageFromServerEvent(l[:-1])) 
					# We are done with the message
					l = ''
			except Exception, e:
				print "Exception:",str(e)
				break
	def finish(self):
		print "Cliente fecha conexao"
		self.ccController.evManager.Post(ServerDisconnectedEvent())

